#!/usr/bin/env python
# Download all of a YouTube user's uploads and optionally create a dvd
# version 0.5
"""
This python script is licensed under the GPLv3.
To obtain a copy, view the file COPYING or visit
http://www.gnu.org/copyleft/gpl.html
"""

import os
import re
import sys
import string
import subprocess
import gdata.youtube
import gdata.youtube.service
import feedparser
from optparse import OptionParser
import kaa.metadata
#import pdb

def main():
#    pdb.set_trace()
    parser = OptionParser(
            usage="%prog [options] youtube_user",
            version="%prog 0.5")
    parser.add_option("-f","--format",
            dest="format",
            default=None,
            action="store",
            help="Specify DVD video format (NTSC/PAL). REQUIRED if a DVD is to be created")
    parser.add_option("-d","--dual",
            dest="dual",
            default=False,
            action="store_true",
            help="Target a dual-layer DVD")
    parser.add_option("--remove-files",
            dest="remove",
            default=False,
            action="store_true",
            help="Delete downloaded mp4 files. BE CAREFUL!")
    parser.add_option("-o","--output-dir",
            dest="output",
            default="VIDEO_TS",
            action="store",
            help="Specify output directory. Default: VIDEO_TS")
    parser.add_option("-m","--mirror",
            dest="mirror",
            default=False,
            action="store_true",
            help="Downloads the videos without creating a DVD. Requires the output directory to be specified with -o or --output-dir")
    parser.add_option("-u","--urls-only",
            dest="urls_only",
            default=False,
            action="store_true",
            help="Obtain a list of URLS from the user's upload feed. Video download and DVD creation will be skipped.")
    (options,args) = parser.parse_args()

    if len(args) != 1:
        parser.error("You must specify the Youtube user")
        sys.exit(1)
    else:
        username = str(args[0])

    
    if options.output:
        output_dir = str(options.output)

    if options.urls_only:
        urls_only = True
    else:
        urls_only = False
        if options.dual:
            dual_layer = True
        else:
            dual_layer = False
        if options.mirror:
            mirror = True
        else:
            mirror = False
            if options.remove:
                remove_files = True
            else:
                remove_files = False
        # check for video format once it is determined
        # that a dvd will be made from downloaded videos.
        # (bug found by paldepind on bbs.archlinux.org)
        if options.format:
            video_format = str.lower(options.format)
            if not video_format in ("ntsc","pal"):
                parser.error("You must specify NTSC or PAL with -f FORMAT or --format=FORMAT")
                sys.exit(1)

    # print banner showing commandline arguments
    print "======================================================"
    print "Using options: "
    if urls_only:
        print "\tPrinting URLs only"
    else:
        if mirror:
            print "\tMirroring uploads to local directory"
        else:
            if remove_files:
                print "\tRemove downloaded files after conversion"
            if dual_layer:
                print "\tTarget: Dual-layer DVD(s)"
            print "\tFormat: " + video_format.upper()
            print "\tDVD file output directory: " + output_dir
    print "======================================================"
    
    # begin function calls  =======>>
    (linknum, downloads) = feed_links(username)
    if not urls_only:
        (filelist, dirnum, dirlist) = get_and_convert(linknum, downloads, mirror, dual_layer)
        if not mirror:
            dirlist = make_dvd(video_format, filelist, dirlist, output_dir, dual_layer)
            cleanup(linknum, output_dir, dirnum, remove_files, dirlist)
    print "Done!"
    return
# end function calls    <<=======
    

def feed_links(username):
# get video links from feed.
    username = str(username)
    linknum = 0
    print "Searching for videos by " + username
    BASE_URL = "http://gdata.youtube.com/feeds/api/users/%s/uploads" % username
    print "Using feed URL: " + BASE_URL
    # this will allow the script to download all videos from the user
    # rather than just the first 25 (bug found by Rasi from bbs.archlinux.org)
    for index in range(1,1000,50):
        MOD_URL = BASE_URL + "?start-index=" + str(index) + "&max-results=50"
        feed = feedparser.parse(MOD_URL)
        for en in feed.entries:
            try:
                if re.search(r'watch',en.link):
                    if not en in downloads:
                        linknum = linknum + 1
                        # the [:-22] part strips useless URL parameters
                        print "Found URL #" + str(linknum) + ": " + en.link[:-22]
                        downloads.append(en.link[:-22])
            except:
                pass
    return linknum, downloads

def get_and_convert(linknum, downloads, mirror, dual_layer):
# get videos
    vidnum = 1
    time = 0
    total = 0
    if dual_layer:
        limit = 240
    else:
        limit = 120
    if mirror:
        for vidnum, download in enumerate(downloads):
            print "Downloading video #" + str(vidnum + 1)
            # download the file ONLY, saving with title as filename
            dl = subprocess.Popen(['youtube-dl -bcl ' + download],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            (out, err) = dl.communicate()
        sys.exit(0)
    else:
        # first check to make sure that the output directories don't exist!
        counter = 0
        vidnum = 0
        total = 0
        dirnum = 1
        dirlist = []
        discfiles = []
        for counter in range(100):
            if os.path.isdir("DISC" + str(counter)):
                print "The output directory already exists!"
                print "Exiting to avoid accidentally overwriting files."
                print "Be sure to remove the DISC# directories before"
                print "attempting to run the script again!"
                sys.exit(1)
        os.mkdir("DISC1")
        dirlist.append("DISC1")
        #while vidnum < linknum:
        for vidnum, download in enumerate(downloads):
            if total > limit:
            # increment dirnum and created the new directory
                total = 0
                dirnum = dirnum + 1
                os.mkdir("DISC" + str(dirnum))
                dirlist.append("DISC" + str(dirnum))
                filelist.append(discfiles)
                discfiles = []
            # download videos, saving as <number>.mp4
            print "Downloading video #" + str(vidnum + 1), "from", download
            dl = subprocess.Popen(['youtube-dl -bc -o ' + str(vidnum + 1) + '.mp4 ' + download],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            (out, err) = dl.communicate()
            vidinfo = kaa.metadata.parse(str(vidnum + 1) + '.mp4')
            time = (vidinfo.length/60%60) + 1
            print os.getcwd()
            if (total + time) < limit:
                path = "DISC" + str(dirnum) + "/"
                infile = str(vidnum + 1) + ".mp4"
                outfile = path + str(vidnum + 1) + ".mpg"
                discfiles.append(outfile)
                print os.getcwd()
                print "Moving",infile,"to",outfile
                os.rename(infile, outfile)
                total = total + time

    filelist.append(discfiles)
    return filelist, dirnum, dirlist


def make_dvd(video_format, filelist, dirlist, output_dir, dual_layer):
    """
    # author dvd using tovid
    # make dvd title
    print "Building DVD..."
    title = subprocess.Popen('todisc -noask -files ' + filelist + ' -out VIDEO',shell=True)
    (out, err) = title.communicate()
    # make xml file
    auth = subprocess.Popen('makexml ' + filelist + ' -out DVD',shell=True)
    (out, err) = auth.communicate()
    # create iso
    iso = subprocess.Popen('makedvd -noask -author DVD.xml',shell=True)
    (out, err) = auth.communicate()
    """

    """
    # do everything using any2dvd
    print "Building DVD..."
    auth = subprocess.Popen(['any2dvd --format=ntsc --iso=DVD.iso -j DVD=' + filelist],shell=True)
    (out, err) = auth.communicate()
    """

    # make a movie-only dvd
    print "Directories:", dirlist
    for dirnum, dirname in enumerate(dirlist):
        print "Building DVD from files in " + dirname
        print "Filelist:", filelist[dirnum]
        auth = subprocess.Popen(['movie-to-dvd -M -o ' + dirname + '/' + output_dir + ' -m ' + video_format + ' ' + ' '.join(filelist[dirnum])],shell=True)
        (out, err) = auth.communicate()

    return dirlist


def cleanup(linknum, output_dir, dirnum, remove_files, dirlist):
    # remove temporary video files
    print "Removing temporary video files..."
    path = ""
    for counter in range(1,100):
        path = "DISC" + str(counter) + "/" 
        for vidnum in range(1,100):
            if os.path.isfile(path + str(vidnum) + '.mpg'):
                os.remove(path + str(vidnum) + '.mpg')
                print "\tRemoved", path + str(vidnum) + '.mpg'
        # remove downloaded files if requested
        if remove_files == True:
            print "Removing downloaded video files..."
            for vidnum in range(1,100):
                # delete flv file if it exists
                if os.path.isfile(path + str(vidnum) + '.flv'):
                    os.remove(path + str(vidnum) + '.flv')
                    print "\tRemoved", path + str(vidnum) + '.flv'
                # delete mp4 file if it exists
                if os.path.isfile(path + str(vidnum) + '.mp4'):
                    os.remove(path + str(vidnum) + '.mp4')
                    print "\tRemoved", path + str(vidnum) + '.mp4'
    # rename generic vobs to VIDEO_TS style
    print "Organizing converted files..."
    output_dir = output_dir + "/"
    for dir in dirlist:
        path = dir + "/"
        for vidnum in range(1,100):
            file = str(vidnum) + ".vob"
            infile = path + output_dir + file
            outfile = path + output_dir + 'VTS_01_' + file
            if os.path.isfile(infile):
                os.rename(infile, outfile)
                print "Moved",infile,"to",outfile

    return


if __name__ == "__main__":
    try:
        # initialize variables
        video_format = "" # video format
        downloads = []  # list of download links
        files = []      # working list of converted files
        filelist = []   # list of video files to send to authoring program
        discfiles = []  # list of video files separated by disc
        vidinfo = []    # video information (needed to get video length)
        dirlist = ""    # list of disc output directories
        vidnum = 0      # video download counter
        linknum = 0     # link counter
        dirnum = 1      # directory counter: DISC1, DISC2, ...
        main()
    except:
        print 
        pass

sys.exit(1)
# END OF SCRIPT
